﻿/*
   Copyright 2012 University of Southampton

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections.ObjectModel;
using System.Configuration.Install;
using System.Collections;
using System.Diagnostics;
using System.IO;
using uk.ac.soton.ses.DAL;

namespace uk.ac.soton.ses
{
    public partial class DataCollectionForm : Form
    {
        HDCConfiguration _configuration = null;
        string _binDirectory = "";

        public DataCollectionForm()
        {
            InitializeComponent();
            this.LoadConfiguration();
            this._binDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(DataCollectionForm)).Location);
        }


        //Event handling
        #region Event Handling

        private void DataCollectionForm_Load(object sender, EventArgs e)
        {
            this.PopulateFormFromConfig();
            //if (!this._configuration.DatabaseConnectionValid())
            //{
            //        this.WriteMessage("Database connection not working. Check settings.");
            //}
        }

        private void btnBrowseForHDCFolder_Click(object sender, EventArgs e)
        {
            DialogResult result = folderBrowserDialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                this.txtHDCLocalPath.Text = folderBrowserDialog.SelectedPath;
            }
        }

        private void btnQuit_Click(object sender, EventArgs e)
        {
            this.Close();
            Application.Exit();
        }

        private void btn_SaveDatabaseSettings_Click(object sender, EventArgs e)
        {
            this.SaveChangesToDatabase();
        }

        private void btn_CreateMetadataDatabase_Click(object sender, EventArgs e)
        {
            this.InstallDatabase(this.txtDatabaseServer.Text, this.txtDatabaseName.Text);
            if (this.SaveChangesToConfigFile(force: false))
            {
                this.LoadConfiguration();
                this.PopulateFormFromConfig();
            }
        }

        private void btn_InstallSharePointToolkit_Click(object sender, EventArgs e)
        {
            if (this.SaveChangesToConfigFile())
            {
                this.LoadConfiguration();
                this.PopulateFormFromConfig();
                this.InstallSharePointSolutionPackage();
            }
        }

        private void btn_InstallFileMonitoringService_Click(object sender, EventArgs e)
        {
            if (this.SaveChangesToConfigFile())
            {
                this.LoadConfiguration();
                this.PopulateFormFromConfig();
                this.InstallFileSystemWatcherService();
            }
        }

        private void btnRefreshDataFromDatabase_Click(object sender, EventArgs e)
        {
            if (this.SaveChangesToConfigFile())
            {
                this.LoadConfiguration();
                this.PopulateFormFromConfig();
            }
        }

        private void btn_CreateNewSharePointContainer_Click(object sender, EventArgs e)
        {
            this._configuration.CreateNewSharePointContainer();
            this._configuration.SaveChangesToFile(true);
            this.LoadConfiguration();
            this.PopulateFormFromConfig();
        }


        private void btn_CreateNewFileSystemWatcherContainer_Click(object sender, EventArgs e)
        {
            this._configuration.CreateNewFileSystemWatcherContainer();
            this._configuration.SaveChangesToFile(true);
            this.LoadConfiguration();
            this.PopulateFormFromConfig();
        }

        private void btnSaveConfigurationFile_Click(object sender, EventArgs e)
        {
            this.SaveChangesToConfigFile();
        }
        
        #endregion


        //Form related functions
        #region Form related functions

        private bool SaveChangesToConfigFile(bool force=false)
        {
            this.GetNewSettingsFromForm();
            if (!this._configuration.DatabaseConnectionValid() && !force)
            {
                this.WriteMessage("Database connection not working. Check settings.");
                return false;
            }
            if (this.ContainersValid() || force)
            {
                this._configuration.SaveChangesToFile(true);
                return true;
            }
            else
            {
                return false;
            }
        }

        private bool SaveChangesToDatabase()
        {
            this.GetNewSettingsFromForm();

            //Save changes
            try
            {
                //Try to save
                this._configuration.SaveChangesToDatabase();
                //Report to success to user
                this.WriteMessage("Changes saved.");
                return true;
            }
            catch (EntityException e)
            {
                this.WriteMessage("Cannot connect to database. Please check server details are correct.");
                this.WriteMessage(String.Format("Error was: {0}.", e.Message));
                return false;
            }
        }

        private void LoadConfiguration()
        {
            this._configuration = new HDCConfiguration();
            if (!this._configuration.DatabaseConnectionValid())
            {
                this.WriteMessage("Cannot connect to database. Please check server details are correct.");
            }
                 //Check that containers are valid
            else if (!this.ContainersValid())
            {
                this.WriteMessage("Problem with configuration containers");
            }
        }

        private bool ContainersValid()
        {
            bool isValid = true;
            try
            {
                using (MaterialsMetadataContext dbcontext = new MaterialsMetadataContext(this._configuration.ConfigurationOptions.DatabaseOptions.EntityConnectionString))
                {
                    Experiment filesystemwatcherContainer = dbcontext.Experiments.Include("ExperimentType").FirstOrDefault(exp => exp.ID == this._configuration.ConfigurationOptions.FileSystemWatcherOptions.ConfigurationContainerID);
                    Experiment sharepointContainer = dbcontext.Experiments.Include("ExperimentType").FirstOrDefault(exp => exp.ID == this._configuration.ConfigurationOptions.SharePointOptions.ConfigurationContainerID);
                    if (filesystemwatcherContainer == null)
                    {
                        isValid = false;
                        this.WriteMessage(String.Format("File system watcher options container {0} doesn't exist.", this._configuration.ConfigurationOptions.FileSystemWatcherOptions.ConfigurationContainerID));
                    }
                    else if (filesystemwatcherContainer.ExperimentType.ID != (int)HDCExperimentTypes.FileStoreOptions)
                    {
                        isValid = false;
                        this.WriteMessage(String.Format("Container {0} does not have correct type for file system watcher options.", this._configuration.ConfigurationOptions.FileSystemWatcherOptions.ConfigurationContainerID));
                    }
                    if (sharepointContainer == null)
                    {
                        isValid = false;
                        this.WriteMessage(String.Format("SharePoint options container {0} doesn't exist.", this._configuration.ConfigurationOptions.SharePointOptions.ConfigurationContainerID));
                    }
                    else if (sharepointContainer.ExperimentType.ID != (int)HDCExperimentTypes.SharePointInterfaceOptions)
                    {
                        isValid = false;
                        this.WriteMessage(String.Format("Container {0} does not have correct type for SharePoint options.", this._configuration.ConfigurationOptions.SharePointOptions.ConfigurationContainerID));
                    }
                }
            }
            catch (Exception e)
            {
                this.WriteMessage(String.Format("Exception caused when checking containers: {0}", e.Message));
                isValid = false;
            }
            return isValid;
        }


        private void GetNewSettingsFromForm()
        {
            //Container options
            int newFileSystemWatcherContainerID;
            int newSharePointContainerID;
            if (int.TryParse(this.txtFileSystemWatcherConfigurationContainerID.Text, out newFileSystemWatcherContainerID))
            {
                this._configuration.ConfigurationOptions.FileSystemWatcherOptions.ConfigurationContainerID = newFileSystemWatcherContainerID;
            }
            if (int.TryParse(this.txtSharePointConfigurationContainerID.Text, out newSharePointContainerID))
            {
                this._configuration.ConfigurationOptions.SharePointOptions.ConfigurationContainerID = newSharePointContainerID;
            }
            //Database options
            this._configuration.ConfigurationOptions.DatabaseOptions.DatabaseName = this.txtDatabaseName.Text;
            this._configuration.ConfigurationOptions.DatabaseOptions.DatabaseServer = this.txtDatabaseServer.Text;
            //SharePoint options
            this._configuration.ConfigurationOptions.SharePointOptions.SiteCollectionUrl = this.txtSharePointSiteCollectionURL.Text;
            //File share options
            this._configuration.ConfigurationOptions.FileSystemWatcherOptions.LocalPath = this.txtHDCLocalPath.Text;
            this._configuration.ConfigurationOptions.FileSystemWatcherOptions.UNCPath = this.txtHDCUNCPath.Text;
            this._configuration.ConfigurationOptions.FileSystemWatcherOptions.WebPath = this.txtHDCWebPath.Text;

            int basePathDepthInWatchFolder;
            if (int.TryParse(this.txtBasePathDepthInWatchFolder.Text, out basePathDepthInWatchFolder))
            {
                this._configuration.ConfigurationOptions.FileSystemWatcherOptions.BasePathDepthInWatchFolder = basePathDepthInWatchFolder;
            }

            int loggingVerbosity;
            if (int.TryParse(this.txtLoggingVerbosity.Text, out loggingVerbosity)
                && loggingVerbosity >= (int)TraceLevel.Off
                && loggingVerbosity <= (int)TraceLevel.Verbose
                )
            {
                this._configuration.ConfigurationOptions.FileSystemWatcherOptions.LoggingVerbosity = (TraceLevel)loggingVerbosity;
            }

            this._configuration.ConfigurationOptions.FileSystemWatcherOptions.TrackingFileName = this.txtTrackingFileName.Text;
            this._configuration.ConfigurationOptions.FileSystemWatcherOptions.TrackingFolderName = this.txtTrackingFolderName.Text;
            this._configuration.ConfigurationOptions.FileSystemWatcherOptions.FolderNamesToIgnore = this.txtFolderNamesToIgnore.Text.Split('|');
            this._configuration.ConfigurationOptions.FileSystemWatcherOptions.FileNamesToIgnore = this.txtFileNamesToIgnore.Text.Split('|');
        }

        private void PopulateFormFromConfig()
        {
            //Container options
            this.lblFileSystemConfigurationContainerID.Text = this._configuration.ConfigurationOptions.FileSystemWatcherOptions.ConfigurationContainerID.ToString();
            this.lblSharePointConfigurationContainerID.Text = this._configuration.ConfigurationOptions.SharePointOptions.ConfigurationContainerID.ToString();
            this.txtFileSystemWatcherConfigurationContainerID.Text = this._configuration.ConfigurationOptions.FileSystemWatcherOptions.ConfigurationContainerID.ToString();

            this.txtBasePathDepthInWatchFolder.Text = this._configuration.ConfigurationOptions.FileSystemWatcherOptions.BasePathDepthInWatchFolder.ToString();
            this.txtTrackingFileName.Text = this._configuration.ConfigurationOptions.FileSystemWatcherOptions.TrackingFileName;
            this.txtTrackingFolderName.Text = this._configuration.ConfigurationOptions.FileSystemWatcherOptions.TrackingFolderName;
            this.txtFolderNamesToIgnore.Text = String.Join("|", this._configuration.ConfigurationOptions.FileSystemWatcherOptions.FolderNamesToIgnore??new string[0]);
            this.txtFileNamesToIgnore.Text = String.Join("|", this._configuration.ConfigurationOptions.FileSystemWatcherOptions.FileNamesToIgnore??new string[0]);

            this.txtSharePointConfigurationContainerID.Text = this._configuration.ConfigurationOptions.SharePointOptions.ConfigurationContainerID.ToString();
            //Database options
            this.txtDatabaseName.Text = this._configuration.ConfigurationOptions.DatabaseOptions.DatabaseName;
            this.txtDatabaseServer.Text = this._configuration.ConfigurationOptions.DatabaseOptions.DatabaseServer;
            //SharePoint options
            this.txtSharePointSiteCollectionURL.Text = this._configuration.ConfigurationOptions.SharePointOptions.SiteCollectionUrl;
            //File share option
            this.txtHDCLocalPath.Text = this._configuration.ConfigurationOptions.FileSystemWatcherOptions.LocalPath;
            this.txtHDCUNCPath.Text = this._configuration.ConfigurationOptions.FileSystemWatcherOptions.UNCPath;
            this.txtHDCWebPath.Text = this._configuration.ConfigurationOptions.FileSystemWatcherOptions.WebPath;
            this.txtLoggingVerbosity.Text = ((int)this._configuration.ConfigurationOptions.FileSystemWatcherOptions.LoggingVerbosity).ToString();
            //Config file contents
            this.txtConfigFileContents.Text = this.GetConfigFileContents();
        }

        private void WriteMessage(string message, bool appendNewLine=true)
        {
            this.txtMessages.Text += message;
            if(appendNewLine) this.txtMessages.Text += Environment.NewLine;
        }



        private string GetConfigFileContents()
        {
            if (File.Exists(this._configuration.ConfigFilePath))
            {
                using (StreamReader stream = File.OpenText(this._configuration.ConfigFilePath))
                {
                    return stream.ReadToEnd();
                }
            }
            else
            {
                return "File doesn't exist";
            }
        }

        #endregion


        //Installation Actions
        #region Installation Actions

        private bool InstallDatabase(string databaseServer, string databaseName)
        {
            //string databaseServer = this._configuration.ConfigurationOptions.DatabaseOptions.DatabaseServer;
            //string databaseName = this._configuration.ConfigurationOptions.DatabaseOptions.DatabaseName;

            this.WriteMessage(
                String.Format("Creating database {0} on server {1}...", databaseName, databaseServer),
                appendNewLine: false
                );

            //Creation of the database is handled by an external library
            HDCDatabaseCreator.CreateHDCDatabase(databaseServer, "HDCMetadata", databaseName);

            //TODO: need to add a check to see if database creation was successful instead of just returning true
            bool success = true;

            if (success)
                this.WriteMessage("done.");
            else
                this.WriteMessage("failed.");
            return true;
        }

        private bool InstallFileSystemWatcherService()
        {
            this.WriteMessage("Installing file system monitor...", appendNewLine: false);

            ProcessStartInfo processInfo = new ProcessStartInfo();
            processInfo.FileName = Path.Combine(this._binDirectory, "HDCMetadataSyncService.exe");
            processInfo.Arguments = "/install";
            Process process = Process.Start(processInfo);
            process.WaitForExit();

            bool success = process.ExitCode == 0;

            if (success)
                this.WriteMessage("done.");
            else
                this.WriteMessage("failed.");
           
            return success;
        }

        private bool InstallSharePointSolutionPackage()
        {
            this.WriteMessage(
                String.Format("Installing SharePoint toolkit to URL {0}...", this._configuration.ConfigurationOptions.SharePointOptions.SiteCollectionUrl),
                appendNewLine: false
                );

            string siteCollectionUrl = this._configuration.ConfigurationOptions.SharePointOptions.SiteCollectionUrl;
            string wspFile = Path.Combine(this._binDirectory, "HDCSharePointToolkit.wsp");

            ProcessStartInfo processInfo = new ProcessStartInfo();
            processInfo.FileName = Path.Combine(this._binDirectory, "HDCSharePointToolkitDeploy.exe");
            processInfo.Arguments = String.Format("install /wspfile=\"{0}\" /sitecollection=\"{1}\"", wspFile, siteCollectionUrl);
            Process process = Process.Start(processInfo);
            process.WaitForExit();

            bool success = process.ExitCode == 0;

            if (success)
                this.WriteMessage("done.");
            else
                this.WriteMessage(String.Format("failed. Could not install SharePoint toolkit to URL of {0}", this._configuration.ConfigurationOptions.SharePointOptions.SiteCollectionUrl));
            
            return success;
        }

        #endregion



    }
}
